var mongoose = require('mongoose')
    Schema = mongoose.Schema;
var schema = new Schema({
    name: String,
    next: [mongoose.Schema.Types.ObjectId],
    content: [mongoose.Schema.Types.ObjectId],
    refId: {
        type: mongoose.Schema.Types.ObjectId,
        default: null
    }
}),
    fn = schema.methods,
    modelFn = schema.statics;

modelFn.copy = function(parent_id, [..._ids]) {
    return model.find({}).where('_id').in(_ids).then(docs => {
        return Promise.all(
            docs.map(doc => {
                return new model({
                    name: doc.name,
                    next: doc.next.slice(),
                    content: doc.content.slice(),
                    refId: doc._id
                }).save();
            })
        )
    })
    .then(docs => {
        return model.addNext(parent_id, docs.map(x => x._id))
        .then(parentDoc => {
            return Promise.resolve([parentDoc, docs]);
        });
    })
}

modelFn.move = function(parent_id, [..._id], dest_id) {
    var removedArr = [];
    return model.removeNext(parent_id, _id, removedArr)
    .then(parent_doc => {
        return model.addNext(dest_id, removedArr)
        .then(dest_doc => {
            return Promise.resolve([parent_doc, dest_doc])
        });
    })
}

modelFn.create = function(directory) {
    return new model({
        name: directory,
        next: [],
        content: []
    }).save();
}

modelFn.read = function(_id) {
    return model.findById(_id).exec();
}

modelFn.delete = function(_id) {
    return model.read(_id).then(doc => doc.remove());
}

modelFn.addNext = function(parent_id, [...child_id]) {
    return model
        .findById(parent_id).exec()
        .then(function(doc) {
            doc.next.addToSet.apply(doc.next, child_id);
            doc.markModified('next');
            return doc.save();
        })
}

modelFn.removeNext = function(parent_id, [...child_id], removedArr) {
    return model
        .findById(parent_id).exec()
        .then(function(doc) {
            child_id.forEach(_id => {
                var index = doc.next.indexOf(_id);
                if (index != -1) {
                    doc.next.splice(index, 1);
                    removedArr && removedArr.push(_id);
                    doc.markModified('next');
                }
            })
            return doc.save();
        })
}

modelFn.addImages = function(_id, [...image_ids]) {
    return model
        .findById(_id).exec()
        .then(function(doc) {
            doc.content.addToSet.apply(doc.content, image_ids);
            doc.markModified('content');
            return doc.save();
        })
}

modelFn.removeImages = function(_id, [...image_ids], arr) {
    return model
        .findById(_id).exec()
        .then(function(doc) {
            image_ids.forEach((image_id) => {
                var index = doc.content.indexOf(image_id);
                if (index != -1) {
                    doc.content.splice(index, 1);
                    arr && arr.push(image_id)
                }
            });
            
            doc.markModified('content');
            return doc.save();
        })
}

modelFn.rename = function(_id, newName) {
    return model.findById(_id).exec()
    .then(function(doc) {
        doc.name = newName;
        doc.markModified('name');
        return doc.save();
    });
}

modelFn.listAll = function() {
    return model.find({}).exec();
}

modelFn.listNext = function(_id) {
    return model.findById(_id).then(function(doc) {
        return model.find({}).where('_id').in(doc.next).then((nextDocs) => {
            return Promise.resolve([doc, nextDocs]);
        });
    })
}

modelFn.isValidToAdd = function(parent_id, _id) {
    return model.findById(_id).then(doc => {
        return model.listNext(parent_id)
        .then(([parent_doc, nextDocs]) => {
            var valid = true;
            nextDocs.forEach(d => {
                if (d.name == doc.name || d._id == doc._id) {
                    valid = false;
                }
            })
            return valid ? Promise.resolve() : Promise.reject();
        })
    })
}

modelFn.parentsOf = function(_id) {
    return model.find({}).where('next').in([_id]).exec();
}

modelFn.directoriesOf = function(image_id) {
    return model.find({}).where('content').in([image_id]).exec();
}

var model = mongoose.model('directory', schema);
module.exports = model;